package ca

import (
	"encoding/json"
	"fmt"
	"gitee.com/wayjin/fabric-api/crypto"
)

type KeyStore interface {
	GetSignCert() []byte
	GetCACert() []byte
	GetKey() crypto.Key
	Marshal() ([]byte, error)
}

type cryptoCert struct {
	signcert []byte
	key      crypto.Key
	cacert   []byte
}

func (c cryptoCert) GetSignCert() []byte {
	return c.signcert
}

func (c cryptoCert) GetCACert() []byte {
	return c.cacert
}

func (c cryptoCert) GetKey() crypto.Key {
	return c.key
}

func (c cryptoCert) GetKeyBytes(pwd []byte) ([]byte, error) {
	return nil, nil
}

func (c cryptoCert) Marshal() ([]byte, error) {
	keyBytes, err := crypto.GetPEMFromPrivateKey(c.key)
	if err != nil {
		return nil, err
	}
	obj := cryptoCert_marshal{
		Signcert: c.signcert,
		Keycert:  keyBytes,
		CAcert:   c.cacert,
	}
	return json.Marshal(obj)
}

type cryptoCert_marshal struct {
	Signcert []byte `json:"signcert"`
	Keycert  []byte `json:"keycert"`
	CAcert   []byte `json:"cacert"`
}

// LoadKeyStoreFromBytes: create KeyStore from bytes
func LoadKeyStoreFromBytes(raw []byte) (KeyStore, error) {
	var obj cryptoCert_marshal
	err := json.Unmarshal(raw, &obj)
	if err != nil {
		return nil, err
	}
	key, err := crypto.GetPrivateKeyFromPEM(obj.Keycert, nil)
	if err != nil {
		return nil, err
	}
	return cryptoCert{
		signcert: obj.Signcert,
		key:      key,
		cacert:   obj.CAcert,
	}, nil
}

func NewKeyStore(cert []byte, key PrivateKey, cacert []byte) (KeyStore, error) {
	prk, ok := key.(privateKey)
	if !ok {
		return nil, fmt.Errorf("invald key")
	}
	return cryptoCert{
		signcert: cert,
		key:      prk.key,
		cacert:   cacert,
	}, nil
}

type PrivateKey interface {
	FileName() string
	Bytes() ([]byte, error)
	DeepCopyPrivateKey() PrivateKey
}

func NewPrivateKeyFromBytes(keyBytes []byte) (PrivateKey, error) {
	k, err := crypto.GetPrivateKeyFromPEM(keyBytes, []byte(""))
	if err != nil {
		return nil, err
	}
	return NewPrivateKey(k), nil
}

func NewPrivateKey(k crypto.Key) PrivateKey {
	return privateKey{key: k}
}

type privateKey struct {
	key crypto.Key
}

func (pk privateKey) FileName() string {
	return fmt.Sprintf("%x_sk", pk.key.SKI())
}

func (pk privateKey) Bytes() ([]byte, error) {
	return crypto.GetPEMFromPrivateKey(pk.key)
}

func (pk privateKey) DeepCopyPrivateKey() PrivateKey {
	return &pk
}
